<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stream video with RTCPeerConnection</title>
</head>
<body>
    <video id="localVideo" autoplay></video>
    <video id="remoteVideo" autoplay></video>

    <div>
        <button id="startButton">Start</button>
        <button id="callButton">Call</button>
        <button id="hangupButton">Hang Up</button>
    </div>
</body>
<script src="./js/adapter.js"></script>
<script type="text/javascript">
    'use strict';

    var startButton = document.getElementById('startButton');
    var callButton = document.getElementById('callButton');
    var hangupButton = document.getElementById('hangupButton');
    callButton.disabled = true;
    hangupButton.disabled = true;
    startButton.onclick = start;
    callButton.onclick = call;
    hangupButton.onclick = hangup;

    var startTime;
    var localVideo = document.getElementById('localVideo');
    var remoteVideo = document.getElementById('remoteVideo');

    localVideo.addEventListener('loadedmetadata', function() {
        trace('Local video videoWidth: ' + this.videoWidth +
                'px,  videoHeight: ' + this.videoHeight + 'px');
    });

    remoteVideo.addEventListener('loadedmetadata', function() {
        trace('Remote video videoWidth: ' + this.videoWidth +
                'px,  videoHeight: ' + this.videoHeight + 'px');
    });

    remoteVideo.onresize = function() {
        trace('Remote video size changed to ' +
                remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight);
        // We'll use the first onresize callback as an indication that video has started
        // playing out.
        if (startTime) {
            var elapsedTime = window.performance.now() - startTime;
            trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
            startTime = null;
        }
    };

    var localStream;
    var pc1;
    var pc2;
    var offerOptions = {
        offerToReceiveAudio: 1,
        offerToReceiveVideo: 1
    };

    function getName(pc) {
        return (pc === pc1) ? 'pc1' : 'pc2';
    }

    function getOtherPc(pc) {
        return (pc === pc1) ? pc2 : pc1;
    }

    function gotStream(stream) {
        trace('Received local stream');
        localVideo.srcObject = stream;
        // Add localStream to global scope so it's accessible from the browser console
        window.localStream = localStream = stream;
        callButton.disabled = false;
    }

    function start() {
        trace('Requesting local stream');
        startButton.disabled = true;
        navigator.mediaDevices.getUserMedia({
                    audio: true,
                    video: true
                })
                .then(gotStream)
                .catch(function(e) {
                    alert('getUserMedia() error: ' + e.name);
                });
    }

    function call() {
        callButton.disabled = true;
        hangupButton.disabled = false;
        trace('Starting call');
        startTime = window.performance.now();
        var videoTracks = localStream.getVideoTracks();
        var audioTracks = localStream.getAudioTracks();
        if (videoTracks.length > 0) {
            trace('Using video device: ' + videoTracks[0].label);
        }
        if (audioTracks.length > 0) {
            trace('Using audio device: ' + audioTracks[0].label);
        }

        const configuration = {
            iceServers: [{
                urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
            }]
        };
        var servers = null;
        // Add pc1 to global scope so it's accessible from the browser console
        window.pc1 = pc1 = new RTCPeerConnection(configuration);
        trace('Created local peer connection object pc1');
        pc1.onicecandidate = function(e) {
            onIceCandidate(pc1, e);
        };
        // Add pc2 to global scope so it's accessible from the browser console
        window.pc2 = pc2 = new RTCPeerConnection(configuration);
        trace('Created remote peer connection object pc2');
        pc2.onicecandidate = function(e) {
            onIceCandidate(pc2, e);
        };
        pc1.oniceconnectionstatechange = function(e) {
            onIceStateChange(pc1, e);
        };
        pc2.oniceconnectionstatechange = function(e) {
            onIceStateChange(pc2, e);
        };
        pc2.onaddstream = gotRemoteStream;

        pc1.addStream(localStream);
        trace('Added local stream to pc1');

        trace('pc1 createOffer start');
        pc1.createOffer(
                offerOptions
        ).then(
                onCreateOfferSuccess,
                onCreateSessionDescriptionError
        );
    }

    function onCreateSessionDescriptionError(error) {
        trace('Failed to create session description: ' + error.toString());
    }

    function onCreateOfferSuccess(desc) {
        trace('Offer from pc1\n' + desc.sdp);
        trace('pc1 setLocalDescription start');
        pc1.setLocalDescription(desc).then(
                function() {
                    onSetLocalSuccess(pc1);
                },
                onSetSessionDescriptionError
        );
        trace('pc2 setRemoteDescription start');
        pc2.setRemoteDescription(desc).then(
                function() {
                    onSetRemoteSuccess(pc2);
                },
                onSetSessionDescriptionError
        );
        trace('pc2 createAnswer start');
        // Since the 'remote' side has no media stream we need
        // to pass in the right constraints in order for it to
        // accept the incoming offer of audio and video.
        pc2.createAnswer().then(
                onCreateAnswerSuccess,
                onCreateSessionDescriptionError
        );
    }

    function onSetLocalSuccess(pc) {
        trace(getName(pc) + ' setLocalDescription complete');
    }

    function onSetRemoteSuccess(pc) {
        trace(getName(pc) + ' setRemoteDescription complete');
    }

    function onSetSessionDescriptionError(error) {
        trace('Failed to set session description: ' + error.toString());
    }

    function gotRemoteStream(e) {
        // Add remoteStream to global scope so it's accessible from the browser console
        window.remoteStream = remoteVideo.srcObject = e.stream;
        trace('pc2 received remote stream');
    }

    function onCreateAnswerSuccess(desc) {
        trace('Answer from pc2:\n' + desc.sdp);
        trace('pc2 setLocalDescription start');
        pc2.setLocalDescription(desc).then(
                function() {
                    onSetLocalSuccess(pc2);
                },
                onSetSessionDescriptionError
        );
        trace('pc1 setRemoteDescription start');
        pc1.setRemoteDescription(desc).then(
                function() {
                    onSetRemoteSuccess(pc1);
                },
                onSetSessionDescriptionError
        );
    }

    function onIceCandidate(pc, event) {
        if (event.candidate) {
            getOtherPc(pc).addIceCandidate(
                    new RTCIceCandidate(event.candidate)
            ).then(
                    function() {
                        onAddIceCandidateSuccess(pc);
                    },
                    function(err) {
                        onAddIceCandidateError(pc, err);
                    }
            );
            trace(getName(pc) + ' ICE candidate: \n' + event.candidate.candidate);
        }
    }

    function onAddIceCandidateSuccess(pc) {
        trace(getName(pc) + ' addIceCandidate success');
    }

    function onAddIceCandidateError(pc, error) {
        trace(getName(pc) + ' failed to add ICE Candidate: ' + error.toString());
    }

    function onIceStateChange(pc, event) {
        if (pc) {
            trace(getName(pc) + ' ICE state: ' + pc.iceConnectionState);
            console.log('ICE state change event: ', event);
        }
    }

    function hangup() {
        trace('Ending call');
        pc1.close();
        pc2.close();
        pc1 = null;
        pc2 = null;
        hangupButton.disabled = true;
        callButton.disabled = false;
    }


    function trace(text) {
        if (text[text.length - 1] === '\n') {
            text = text.substring(0, text.length - 1);
        }
        if (window.performance) {
            var now = (window.performance.now() / 1000).toFixed(3);
            console.log(now + ': ' + text);
        } else {
            console.log(text);
        }
    }
</script>
</html>